A Rust crate for helping parse binary data using ✨macro magic✨.
# Example
```
# use binread::{prelude::*, io::Cursor, NullString};
#[derive(BinRead)]
#[br(magic = b"DOG", assert(name.len() != 0))]
struct Dog {
bone_pile_count: u8,
#[br(big, count = bone_pile_count)]
bone_piles: Vec,
#[br(align_before = 0xA)]
name: NullString
}
let mut reader = Cursor::new(b"DOG\x02\x00\x01\x00\x12\0\0Rudy\0");
let dog: Dog = reader.read_ne().unwrap();
assert_eq!(dog.bone_piles, &[0x1, 0x12]);
assert_eq!(dog.name.into_string(), "Rudy")
```
# The Basics
At the core of `binread` is the [`BinRead`](BinRead) trait. It defines how to read
a type from bytes and is already implemented for most primitives and simple collections.
```rust
use binread::{BinRead, io::Cursor};
let mut reader = Cursor::new(b"\0\0\0\x01");
let val = u32::read(&mut reader).unwrap();
```
However, [`read`](BinRead::read) is intentionally simple and, as a result, doesn't even
allow you to configure the byte order. For that you need [`read_options`](BinRead::read_options)
which, while more powerful, isn't exactly ergonomics.
So, as a balance between ergonomics and configurability you have the [`BinReaderExt`](BinReaderExt)
trait. It is an extension for readers to allow for you to directly read any BinRead types from
any reader.
Example:
```rust
use binread::{BinReaderExt, io::Cursor};
let mut reader = Cursor::new(b"\x00\x0A");
let val: u16 = reader.read_be().unwrap();
assert_eq!(val, 10);
```
It even works for tuples and arrays of BinRead types for up to size 32.
# Derive Macro
The most significant feature of binread is its ability to use the Derive macro to
implement [`BinRead`](BinRead) for your own types. This allows you to replace repetitive
imperative code with declarative struct definitions for your binary data parsing.
## Basic Derive Example
```rust
# use binread::BinRead;
#[derive(BinRead)]
struct MyType {
first: u32,
second: u32
}
// Also works with tuple types!
#[derive(BinRead)]
struct MyType2(u32, u32);
```
## Attributes
The BinRead derive macro uses attributes in order to allow for more complicated parsers. For
example you can use `big` or `little` at either the struct-level or the field-level in order
to override the byte order of values.
```rust
# use binread::{prelude::*, io::Cursor};
#[derive(BinRead)]
#[br(little)]
struct MyType (
#[br(big)] u32, // will be big endian
u32, // will be little endian
);
```
The order of precedence is: (from highest to lowest)
1. Field-level
2. Variant-level (for enums)
3. Top-level
4. Configured (i.e. what endianess was passed in)
5. Native endianess
For a list of attributes see the [`attribute`](attribute) module
## Generics
The BinRead derive macro also allows for generic parsing. That way you can build up
higher-level parsers that can have their type swapped out to allow greater reuse of code.
```rust
# use binread::{prelude::*, io::Cursor};
#[derive(BinRead)]
struct U32CountVec> {
count: u32,
#[br(count = count)]
data: Vec,
}
```
In order to parse generically, we have to (in some way) bound `Args`. The easiest way to do
this is to bound `::Args` to `()` (no arguments), however it is also possible to
either accept a specific set of arguments or be generic over the given arguments.
## Features
* `const_generics` - Change array [`BinRead`] implementation to use const generics
* `std` - Disable this feature to enable `no_std` support, on by default